package com.slsoft.sys.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import cn.fastmc.code.jpa.dao.SpringJpaDao;
import cn.fastmc.core.ServiceException;
import cn.fastmc.core.TreeDataProvider;
import cn.fastmc.core.jpa.service.BaseService;
import cn.fastmc.viewconfig.components.FormItem;
import cn.fastmc.viewconfig.components.ListDataLoad;
import cn.fastmc.viewconfig.components.UITreeNode;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.slsoft.auth.entify.Privilege;
import com.slsoft.auth.entify.Privilege.PrivilegeTypeEnum;
import com.slsoft.auth.service.PrivilegeService;
import com.slsoft.sys.dao.MenuDao;
import com.slsoft.sys.entify.Menu;
import com.slsoft.sys.entify.Menu.MenuTypeEnum;

@Service
@Transactional
public class MenuService extends BaseService<Menu, String> implements TreeDataProvider,ListDataLoad {

    @Autowired
    private MenuDao menuDao;



    @Autowired
    private PrivilegeService privilegeService;

    @Autowired
    private SecurityMetadataSource securityMetadataSource;

    @Override
    protected SpringJpaDao<Menu, String> getEntityDao() {
        return menuDao;
    }
    
    @Transactional(readOnly = true)
    public List<Menu> findRoots() {
        List<Menu> roots = Lists.newArrayList();
        Iterable<Menu> allMenus = menuDao.findAllCached();
        for (Menu menu : allMenus) {
            if (menu.getParent() == null) {
                roots.add(menu);
            }
        }
        Collections.sort(roots);
        return roots;
    }
    
    @Transactional(readOnly = true)
    public Iterable<Menu> findAll() {
    	 Iterable<Menu> allMenus = menuDao.findAllCached();
    	 return allMenus;
    }
    @Transactional(readOnly = true)
    public List<Menu> findChildren(String parentId) {
    	Assert.notNull(parentId, "findChildren 'parentId' must not be null");
        List<Menu> items = Lists.newArrayList();
        Iterable<Menu> allMenus = menuDao.findAllCached();
        for (Menu menu : allMenus) {
            if (menu.getParent()!=null && parentId.equals(menu.getParent().getId())) {
                items.add(menu);
            }
        }
        Collections.sort(items);
        return items;
    }
   
    public List<UITreeNode> authUserMenu(Set<GrantedAuthority> authorities, String currentWebContextPath) {
    	  List<UITreeNode> menuVOs =  new ArrayList<UITreeNode>();
    	  List<Menu> roots = this.findRoots();
    	  for (Menu root : roots) {
              loopMenu(null, authorities, menuVOs, root, currentWebContextPath);
          }
    	  //过滤掉不显示的没有子项目的菜单项
    	loopFilterEmptyMenu(menuVOs);   
    	return menuVOs;
    }
    /**
     * 过虑用于前台显示的菜单列表
     * @param parent
     * @param authorities
     * @param menuVOs
     * @param menu
     * @param currentWebContextPath
     */
    private void loopMenu(UITreeNode parent, Set<GrantedAuthority> authorities, List<UITreeNode> menuVOs, Menu menu,
            String currentWebContextPath) {
    	if (menu.getDisabled()) {
            return;
        }
    	String menuURL = menu.getUrl();
    	
    	
		if (StringUtils.isNotBlank(menuURL)) {
           if(!filterPrivilegeMenu(menuURL,authorities)){
        	   return ;
           }
		}
		
		StringBuffer href = new StringBuffer();
    	if (MenuTypeEnum.RELC.equals(menu.getType()) || menu.getType() == null) {
            if (menuURL == null) {
                menuURL = "";
            }
            href.append(currentWebContextPath);
            if (StringUtils.isNotBlank(menuURL) && !menuURL.startsWith("/")) {
                href.append("/");
            }
            href.append(menuURL);
            menuURL = href.toString();
        }
		UITreeNode item = new UITreeNode();
    	item.setText(menu.getTitle());	
    	item.setId(String.valueOf(menu.getId()));
    	item.setState(menu.getChildrenSize()>0?"closed":"open");
		Map<String,String>  attribute = Maps.newHashMap();
		attribute.put("code", menu.getCode());
		attribute.put("orderRank",String.valueOf( menu.getOrderRank()));
        if(StringUtils.isNotBlank(menuURL))attribute.put("url", href.toString());
		item.setAttributes(attribute);
		menuVOs.add(item);
        List<Menu> children = findChildren(menu.getId());
        if (!CollectionUtils.isEmpty(children)) {
            List<UITreeNode> childrenList = Lists.newArrayList();
            item.setChildren(childrenList);
            for (Menu child : children) {
                loopMenu(item, authorities, childrenList, child, currentWebContextPath);
            }
        }
    }
    /**
     * 把菜单href转成权限资源通配URL
     * @param menuURL
     * @return
     */
    private String matchedPrivilegeUrl(String menuURL){
    	Assert.notNull(menuURL, "menu 'href' must not be null");
    	StringBuffer matchedUrl = new StringBuffer();
    	if(StringUtils.indexOf(menuURL, "action")>0){
    		matchedUrl.append(StringUtils.substring(menuURL, 0,menuURL.lastIndexOf("/")+1));
    	}else if(StringUtils.endsWith(menuURL, "/")){
    	    matchedUrl.append(menuURL+"/");
    	}else{
    		matchedUrl.append(menuURL);
    	}
    	return matchedUrl.toString();
    }
    /**
     * 过滤有权限的菜单
     * @param menuURL
     * @param crurrentAuthorities
     * @return
     */
    private boolean filterPrivilegeMenu(String menuURL,Set<GrantedAuthority> crurrentAuthorities){
        String matchedUrl = matchedPrivilegeUrl(menuURL);
    	boolean matched = false;
    	 Collection<ConfigAttribute> configAttributes = securityMetadataSource.getAttributes(matchedUrl);
         if (!CollectionUtils.isEmpty(configAttributes)) {
             for (ConfigAttribute configAttribute : configAttributes) {
                 for (GrantedAuthority authority : crurrentAuthorities) {
                     if (authority.getAuthority().equals(configAttribute.getAttribute())) {
                         matched = true;
                         break;
                     }
                 }    
             }            
         }
         return matched;
    }
    /**
     * 过滤掉不显示的没有子项目的菜单项
     * @param menuVOs
     */
    private void loopFilterEmptyMenu(List<UITreeNode> menuVOs){
    	 for(Iterator<UITreeNode> it = menuVOs.iterator();it.hasNext();){
    		 UITreeNode item = it.next();
    		 List<UITreeNode>  childens = item.getChildren();
    		 if(CollectionUtils.isEmpty(childens)&&StringUtils.isBlank(item.getAttributes().get("url"))){
    			 it.remove();
    			 continue;
    		 }
    		 loopFilterEmptyMenu(childens);
    	 }
    }

    @Override
    @CacheEvict(value = "SpringSecurityCache", allEntries = true)
    public Menu save(Menu menu) {
        if (menu.isNew()) {
            if (StringUtils.isBlank(menu.getCode())) {
                menu.setCode("M" + RandomStringUtils.randomNumeric(6));
            }
            //同步自动创建的对应权限数据
            String url = menu.getUrl();
            if (StringUtils.isNotBlank(url) && url.startsWith("/")) {
                if (privilegeService.findByProperty("url", url) == null) {
                    Privilege privilege = new Privilege();
                    privilege.setCategory("菜单权限");
                    privilege.setType(PrivilegeTypeEnum.MENU);
                    privilege.setCode("P" + StringUtils.substring(menu.getCode(), 1));
                    privilege.setTitle(menu.getTitle());
                    privilege.setDescription("创建菜单自动创建对应权限");
                    privilege.setUrl(matchedPrivilegeUrl(url));
                    privilegeService.save(privilege);
                }
            }
           
        }
        if(menu.getParent()!=null&&StringUtils.isNotBlank(menu.getParent().getId())){
        	
        	Menu parent = menuDao.findOne(menu.getParent().getId());
        	long size = menuDao.findChildrenSize(parent);
        	parent.setChildrenSize((int)(size+1));
        	menu.setInheritLevel(parent.getInheritLevel()+1);
        	
        }
        Menu self =  menuDao.findOne(menu.getId());
        if(self.getOrderRank() != menu.getOrderRank()){
        	self.setOrderRank(menu.getOrderRank());
    		updateAllChildrenOrderRank(self);
    	}
       return this.saveOrUpdate(menu,self,new String[]{"children"});
    }
    /**
     * 针对父级菜单排序号修改，将对其所有子项排序号进行修改
     * @param self
     */
    private void updateAllChildrenOrderRank(Menu self){
    	Integer orderNum = self.getOrderRank();
    	List<Menu> childrens = self.getChildren();
    	if(!CollectionUtils.isEmpty(childrens)){
    		for(Menu item : childrens){
    			orderNum++;
    			item.setOrderRank(orderNum);
    			updateAllChildrenOrderRank(item);
    		}
    	}
    	
    }
    @Override
    public void delete(Menu entity) {
        //同步清理自动创建的对应权限数据
        String url = entity.getUrl();
        if (StringUtils.isNotBlank(url)) {
            Privilege privilege = privilegeService.findByProperty("url", url);
            if (privilege != null) {
                privilegeService.delete(privilege);
            }
        }
        if(entity.getParent()!=null&&StringUtils.isNotBlank(entity.getParent().getId())){
        	Menu parent = menuDao.findOne(entity.getParent().getId());
        	parent.setChildrenSize(parent.getChildrenSize()-1);
        	
        }
        super.delete(entity);
    }
    /**
     * 用于生成菜单树形数据
     */
    @Override
	public Object[] getChildren(Object userData,HttpServletRequest request) throws ServiceException {
		List<UITreeNode> children = null;
		try{
			children = new ArrayList<UITreeNode>();
			List<Menu> menuchildren = null;
			if (userData == null) {
				menuchildren = findRoots();
			} else {
				String id = (String)userData;
				menuchildren = findChildren(id);
			}
			for(Menu menu  : menuchildren){
					UITreeNode node = new UITreeNode();
					node.setText(menu.getTitle());	
					node.setParentId(String.valueOf(userData));
					node.setId(String.valueOf(menu.getId()));
					node.setState(menu.getChildrenSize()>0?"closed":"open");
					Map<String,String>  attribute = Maps.newHashMap();
					attribute.put("name", menu.getTitle());
					attribute.put("code", menu.getCode());
					attribute.put("url", menu.getUrl());
					attribute.put("orderRank",String.valueOf( menu.getOrderRank()));
					node.setAttributes(attribute);
					children.add(node);

			}}catch(Exception ex){
				logger.error(ex.toString());
				throw new ServiceException(ex);
				
			}
			return children.toArray();
	}
    /**
     *用于生成下列表选择框数据
     */
    @Transactional(readOnly = true)
    public Map<String, String> load(FormItem item, PageContext context) {
		Map<String, String> r = new LinkedHashMap<String, String>();
		Iterable<Menu> menus= menuDao.findAllCached();
		r.put("","无上级");
		for(Menu menu:menus){
			String formatText = "|-";
			for(int i = 0;i < menu.getInheritLevel();i++){
				formatText ="&#160;&#160;"+formatText;
			}
			formatText = formatText+menu.getTitle();
			r.put(menu.getId(),formatText );
		}
		return r;
	}
    

}
